package com.eelye.util.winui.manager;

import com.eelye.util.winui.window.Process;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.WinBase.PROCESS_INFORMATION;
import com.sun.jna.platform.win32.WinBase.STARTUPINFO;
import com.sun.jna.platform.win32.WinDef.DWORD;
import com.sun.jna.platform.win32.WinNT;
import com.sun.jna.platform.win32.WinNT.HANDLE;
import com.sun.jna.ptr.IntByReference;
import org.springframework.stereotype.Service;

@Service
public class ProcessManager {

    /**
     * windows平台，用jna，根据传入的路径，启动应用程序，并返回句柄
     * @Throws Exception 既然指定路径，就希望启动成功，所以如果不成功，就抛出异常
     */
    public static Process launchProcess(String pathToApp) throws Exception {
        Kernel32 kernel32 = Kernel32.INSTANCE;
        HANDLE processHandle = null;
        STARTUPINFO startupInfo = new STARTUPINFO();
        PROCESS_INFORMATION processInfo = new PROCESS_INFORMATION();
        DWORD dword = new DWORD(0);

        boolean success = kernel32.CreateProcess(
                pathToApp,
                null,
                null,
                null,
                false,
                dword,
                null,
                null,
                startupInfo,
                processInfo);

        if (success) {
            processHandle = processInfo.hProcess;
        } else {
            int error = kernel32.GetLastError();
            throw new Exception("Failed to launch application. Error code: " + error);
        }

        return new Process(processHandle, pathToApp);
    }

    public static int waitForProcessExit(Process process) {
        Kernel32 kernel32 = Kernel32.INSTANCE;
        IntByReference exitCode = new IntByReference(0);

        kernel32.WaitForSingleObject(process.getHandle(), Kernel32.INFINITE);
        kernel32.GetExitCodeProcess(process.getHandle(), exitCode);

        return exitCode.getValue();
    }

    /**
     * 关闭程序。有的进程启动后，无法关闭，比如记事本，用管理员启动idea也不行，暂时不知道怎么回事。
     */
    public static boolean terminateProcess(Process process) {
        Kernel32 kernel32 = Kernel32.INSTANCE;
        boolean ret = kernel32.TerminateProcess(process.getHandle(), 0);

        return ret;
    }

    public static HANDLE getProcessHandle(int processId) {
        Kernel32 kernel32 = Kernel32.INSTANCE;
        HANDLE processHandle = kernel32.OpenProcess(
                WinNT.PROCESS_QUERY_INFORMATION, // 查询信息权限
                false, // 是否继承句柄
                processId); // 进程ID

        return processHandle;
    }
}
